home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 November: Tool Chest / Dev.CD Nov 98 TC.toast / Sample Code / Snippets / Sound / SndPlayDoubleBuffer / _source / WAVE.c < prev   
Encoding:
C/C++ Source or Header  |  1996-11-15  |  6.7 KB  |  222 lines  |  [TEXT/CWIE]

  1. /*
  2. **    Apple Macintosh Developer Technical Support
  3. **
  4. **    Routines demonstrating how to parse Microsoft's WAVE sound files.
  5. **
  6. **    by Mark Cookson, Apple Developer Technical Support
  7. **
  8. **    File:    WAVE.c
  9. **
  10. **    Copyright ©1996 Apple Computer, Inc.
  11. **    All rights reserved.
  12. **
  13. **    You may incorporate this sample code into your applications without
  14. **    restriction, though the sample code has been provided "AS IS" and the
  15. **    responsibility for its operation is 100% yours.  However, what you are
  16. **    not permitted to do is to redistribute the source as "Apple Sample
  17. **    Code" after having made changes. If you're going to re-distribute the
  18. **    source, we require that you make it clear in the source that the code
  19. **    was descended from Apple Sample Code, but that you've made changes.
  20. */
  21.  
  22. #include "WAVE.h"
  23.  
  24. /* Please note that this code was written in less than 6 hours, does very little error checking
  25.    and probably will not work for all files.  I have tested it with the WAVE files at my
  26.    disposal and it worked with them.  Your milage may vary.
  27.  
  28.    I do know that it will probably be impossible to get the Mac's IMA decompressor to
  29.    decompress IMA (and ADPCM) compressed WAVE files because the Mac's IMA has a different
  30.    file format from the WAVE file and the decompressor cannot correctly decompress WAVE files.
  31.  
  32.    The Mac IMA compressed file has predictor bytes in the data stream that the WAVE files
  33.    do not have.
  34. */
  35.  
  36. /* Given an WAVE File gets the sample rate and other relavent pieces of information.
  37.    This has been modified from its orignal form found in the Develop 11 MultiBuffer source. */
  38. /*-----------------------------------------------------------------------*/
  39.         OSErr    ASoundGetWAVEHeader        (SoundInfoPtr theSoundInfo,
  40.                                         long *dataStart,
  41.                                         long *length)
  42. /*-----------------------------------------------------------------------*/
  43. {
  44.     WAVETemplatePtr            WAVETemplate;                    /* ...for ease of access */
  45.     long                    filePosition        = kInit,
  46.                             byteCount            = kInit;
  47.     short                    format                = kInit;
  48.     unsigned short            chunkFlags            = kInit;    /* remember chunks we've seen */
  49.     OSErr                    err                    = noErr;
  50.     char                    chunkBuffer[kWAVEChunkBufferSize];
  51.  
  52.     *dataStart = kInit;
  53.  
  54.     /*  Now for the fun part!  We're going to assume that these are generic, non-compressed
  55.             WAVE files and parse accordingly... */
  56.  
  57.     do {
  58.         /*    Position ourselves at the beginning of the next chunk and read in
  59.             a hunk-o-data... */
  60.         err = SetFPos (theSoundInfo->refNum, fsFromStart, filePosition);
  61.         if (err != noErr) {
  62.             DebugPrint ("\pSetFPos failed!");
  63.             break;
  64.         }
  65.  
  66.         byteCount = kWAVEChunkBufferSize;
  67.         err = FSRead (theSoundInfo->refNum, &byteCount, chunkBuffer);                                                /* read a chunk */
  68.         if ((err != noErr) && (err != eofErr)) {
  69.             DebugPrint ("\pFSRead failed!");
  70.             break;
  71.         }
  72.  
  73.         /*    Now, position the template over the data... */
  74.         WAVETemplate = (WAVETemplatePtr) chunkBuffer;
  75.  
  76.         /* assume a failure and break out of the do {} while loop if the next case isn't found.
  77.            if the case is found and no other error is detected, then each case needs to set noErr */
  78.         err = kBadWAVEFileFormat;                                
  79.         switch (WAVETemplate->generic.ckID) {
  80.             case WAVEFORMID:
  81.                 chunkFlags |= kWAVEFORMID;                                                                /* otherwise mark it found */
  82.                 filePosition += 12;
  83.                 err = noErr;
  84.                 break;
  85.             case FormatID:
  86.                 chunkFlags |= kFormatID;                                                                /* otherwise mark it found */
  87.                 format = SwapShort (WAVETemplate->fmt.wFormatTag);
  88.                 theSoundInfo->needsMasking = false;
  89.                 switch (format) {
  90.                     case WAVE_FORMAT_PCM:
  91.                         err = SetupDBHeader (theSoundInfo,
  92.                                             SwapLong (WAVETemplate->fmt.dwSamplesPerSec),
  93.                                             ((SwapShort (WAVETemplate->fmt.wBlockAlign) / SwapShort (WAVETemplate->fmt.wChannels)) * 8),
  94.                                             SwapShort (WAVETemplate->fmt.wChannels),
  95.                                             notCompressed,
  96.                                             NoneType);
  97.                         break;
  98.                     case WAVE_FORMAT_MULAW:
  99.                     case IBM_FORMAT_MULAW:
  100.                         err = SetupDBHeader (theSoundInfo,
  101.                                             SwapLong (WAVETemplate->fmt.dwSamplesPerSec),
  102.                                             ((SwapShort (WAVETemplate->fmt.wBlockAlign) / SwapShort (WAVETemplate->fmt.wChannels)) * 8),
  103.                                             SwapShort (WAVETemplate->fmt.wChannels),
  104.                                             fixedCompression,
  105.                                             kULawSubType);
  106.                         filePosition += 2;    /* This is here because the only µlaw compressed file I ever saw needed it. */
  107.                         break;
  108.                     default:
  109.                         DebugPrint ("\pCan't deal with this file format");
  110.                         err = kUnknownFormat;
  111.                         break;
  112.                 }
  113.                 filePosition += 24;
  114.                 break;
  115.             case WAVEDataID:
  116.                 chunkFlags |= kWAVEDataID;
  117.                 *length = ReverseLong (WAVETemplate->waveData.ckSize);
  118.                 filePosition += 8;
  119.                 *dataStart = filePosition;
  120.                 err = noErr;
  121.                 break;
  122.             /* We don't care about any of these, and my handling of them is probably not correct */
  123.             case WAVEID:
  124.                 err = noErr;
  125.                 filePosition += 4;
  126.                 break;
  127.             case WAVEListID:
  128.                 err = noErr;
  129.                 filePosition += 4;
  130.                 break;
  131.             case SilenceID:
  132.                 err = noErr;
  133.                 filePosition += 4;
  134.                 break;
  135.             case CueID:
  136.                 err = noErr;
  137.                 filePosition += 24;
  138.                 break;
  139.             case FactID:
  140.                 err = noErr;
  141.                 filePosition += 4;
  142.                 break;
  143.             case PlaylistID:
  144.                 err = noErr;
  145.                 filePosition += 12;
  146.                 break;
  147.             case AssocDataID:
  148.                 err = noErr;
  149.                 filePosition += 32;
  150.                 break;
  151.             case LabelID:
  152.                 err = noErr;
  153.                 filePosition += 4;
  154.                 break;
  155.             case NoteID:
  156.                 err = noErr;
  157.                 filePosition += 4;
  158.                 break;
  159.             case TextWithLenID:
  160.                 err = noErr;
  161.                 filePosition += 16;
  162.                 break;
  163.             case EmbededFileID:
  164.                 err = noErr;
  165.                 filePosition += 8;
  166.                 break;
  167.             default:
  168.                 //DebugPrint ("\pSaw a field we didn't know about, this doesn't have to be bad");
  169.                 /* Start walking through the file looking for an ID we know about.
  170.                    This could get ugly, but what the heck... */
  171.                 filePosition += 1;
  172.                 err = noErr;
  173.                 break;
  174.         }
  175.     } while (stillMoreDataWAVEToRead);
  176.  
  177.     if (err != noErr) {
  178.         DebugPrint ("\pError in ASoundGetWAVEHeader");
  179.     }
  180.  
  181.     return err;
  182. }
  183.  
  184. /* These are here for the endian conversion required to parse the header.
  185.    The endian conversion used when playing a WAVE file is much better, don't worry.
  186.  */
  187. short SwapShort (const short theShort) {
  188.     char    tempChar    = kInit;
  189.     short    newShort    = kInit;
  190.  
  191.     tempChar = ((char *)&theShort)[0];
  192.     ((char *)&newShort)[0] = ((char *)&theShort)[1];
  193.     ((char *)&newShort)[1] = tempChar;
  194.  
  195.     return newShort;
  196. }
  197.  
  198. long SwapLong (const long theLong) {
  199.     short    tempShort    = kInit;
  200.     long    newLong        = kInit;
  201.  
  202.     tempShort = SwapShort (((short *)&theLong)[0]);
  203.     ((short *)&newLong)[0] = tempShort;
  204.     tempShort = SwapShort (((short *)&theLong)[1]);
  205.     ((short *)&newLong)[1] = tempShort;
  206.  
  207.     return newLong;
  208. }
  209.  
  210. long ReverseLong (const long theLong) {
  211.     char    tempChar    = kInit,
  212.             i            = kInit;
  213.     long    newLong        = kInit;
  214.  
  215.     for (i = nil; i < 2; i++) {
  216.         tempChar = ((char *)&theLong)[i];
  217.         ((char *)&newLong)[i] = ((char *)&theLong)[3-i];
  218.         ((char *)&newLong)[3-i] = tempChar;
  219.     }
  220.  
  221.     return newLong;
  222. }